package com.zx._07_数据库.jdbc;

import com.github.javafaker.Faker;
import com.google.common.collect.Lists;
import com.zx.common.entity.UserData;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class 造数据 {

    private static final ExecutorService pool = Executors.newFixedThreadPool(Mate.TABLE_NUM * 3);
    private static final Faker faker = new Faker(Locale.CHINA);

    public static void main(final String[] args) throws Exception {
        // 1. 生成数据
        List<UserData> userList = buildData();
        // 按组分表
        final Map<Integer, List<UserData>> indexMap = userList.stream()
                .collect(Collectors.groupingBy(user -> Mate.tableIdx(user.getId())));

        // 2.批量执行
        for (final Entry<Integer, List<UserData>> entry : indexMap.entrySet()) {
            final Integer index = entry.getKey();
            final List<UserData> tableData = entry.getValue();
            final String sql = Mate.getInsertSql(index.longValue());

            pool.execute(() -> {
                Connection con = JDBC.getConnection();
                PreparedStatement ps;
                try {
                    ps = con.prepareStatement(sql);
                    // 分批执行，1000一个提交
                    List<List<UserData>> partition = Lists.partition(tableData, 1000);
                    for (int i = 0; i < partition.size(); i++) {
                        List<UserData> list = partition.get(i);
                        for (UserData user : list) {
                            ps.setLong(1, user.getId());
                            ps.setString(2, user.getRealName());
                            ps.setString(3, user.getCellPhone());
                            ps.setString(4, user.getUniversityName());
                            ps.setString(5, user.getCity());
                            ps.setString(6, user.getStreet());
                            ps.addBatch();
                        }
                        //执行批！
                        ps.executeBatch();
                        log.info("table insert ing, index={}, 进度={}", index, (int) (100D * i / partition.size()));
                    }
                } catch (final SQLException e) {
                    e.printStackTrace();
                }
                log.info("table done, index={}", index);
            });
        }

        pool.shutdown();
    }

    public static List<UserData> buildData() {
        log.info("构建模拟数据, size={}", Mate.TABLE_SIZE);
        List<UserData> resList = Stream.iterate(1, i -> i + 1).limit(Mate.TABLE_SIZE).map(i -> {
            final UserData userInfo = new UserData();
            userInfo.setId(i.longValue());
            userInfo.setRealName(faker.name().fullName());
            userInfo.setCellPhone(faker.phoneNumber().cellPhone());
            userInfo.setCity(faker.address().city());
            userInfo.setStreet(faker.address().streetAddress());
            userInfo.setUniversityName(faker.university().name());
            return userInfo;
        }).collect(Collectors.toList());
        log.info("构建模拟数据, done");
        return resList;
    }

    /**
     * 性能对照组：单线程执行
     * @param args
     * @throws Exception
     */
    public static void main1(final String[] args) throws Exception {
        //然后声明一个Faker对象，你可以根据需要进行本地化声明，如果是使用中国的
        final Faker faker = new Faker(Locale.CHINA);// Locale.US  美国的数据

        final Connection con = JDBC.getConnection();

        for (int i = 1; i < Mate.TABLE_SIZE; i++) {
            final UserData userInfo = new UserData();
            userInfo.setId(i * 1L);
            userInfo.setRealName(faker.name().fullName());
            userInfo.setCellPhone(faker.phoneNumber().cellPhone());
            userInfo.setCity(faker.address().city());
            userInfo.setStreet(faker.address().streetAddress());
            userInfo.setUniversityName(faker.university().name());

            final int index = i % Mate.TABLE_NUM;
            final String sql = "INSERT INTO t_member_" + index
                    + " (id, real_name, cell_phone, university_name, city, street) VALUES(?, ?, ?, ?, ?, ?)";
            final PreparedStatement ps = con.prepareStatement(sql);
            ps.setLong(1, i);
            ps.setString(2, faker.name().fullName());
            ps.setString(3, faker.phoneNumber().cellPhone());
            ps.setString(4, faker.university().name());
            ps.setString(5, faker.address().city());
            ps.setString(6, faker.address().streetAddress());
            ps.execute();
        }
        System.out.println("done");

    }

}
